#!/usr/bin/env python
import os
import httplib
import collections
import sys
import urllib
from prettytable import PrettyTable
import json
import subprocess
import settings
import shutil
import md5
import hashlib
from models import session, Image


_commands = ["image", "volume", "flavor", "server", "network", "port"]



def get_commands_mapping():
    commands_mapping = collections.OrderedDict()
    commands_mapping["image"] = ImageCommand
    commands_mapping["volume"] = VolumeCommand
    commands_mapping["flavor"] = FlavorCommand
    commands_mapping["server"] = ServerCommand
    commands_mapping["network"] = NetworkCommand
    commands_mapping["port"] = PortCommand
    return commands_mapping


def usage(command=None):
    print "Usage:"
    if command:
        if type(command) == type(AbstractCommand) and issubclass(command, AbstractCommand):
            print command.__doc__,
        else:
            print get_commands_mapping()[command].__doc__,
    else:
        for _command in get_commands_mapping().values():
            print _command.__doc__,
    exit(0)




class UsageException(Exception):
    pass


class AbstractCommand(object):

    actions = []
    fields = []

    def __init__(self):
        self.prepare()
        self.table = PrettyTable()
        self.table.field_names = self.fields

    def get_row(self, data):
        return map(lambda x: getattr(data, x, "-"), self.fields)

    def execute(self, action, *args, **kwargs):
        if action in self.actions:
            try:
                getattr(self, action)(*args, **kwargs)
            except UsageException:
                usage(self.__class__)

    def prepare(self):
        try:
            self.image_dir = os.path.join(settings.BASE_DIR, "images")
            if not os.path.exists(settings.BASE_DIR):
                p = subprocess.Popen("sudo mkdir -p {0}".format(settings.BASE_DIR).split(" "))
                p.wait()
                p = subprocess.Popen("sudo chown {0}:{1} {2}".format(os.getuid(), os.getgid(), settings.BASE_DIR).split(" "))
                p.wait()
                os.mkdir(self.image_dir)
        except OSError:
            pass
    

class ImageCommand(AbstractCommand):
    """
    stack image list
    stack image create --file file_name name
    stack image delete uuid
    """
    actions = ["list", "create", "delete"]
    fields = ["id", "name", "checksum"]

    def list(self, *args, **kwargs):
        images = []
        with session() as _session:
            images = _session.query(Image).all()
            for image in images:
                self.table.add_row(self.get_row(image))
        print self.table


    def create(self, *args, **kwargs):
        if len(args) == 3 and  args[0] == "--file":
            hash = hashlib.md5()
            with open(args[1], "rb") as f:
                while True:
                    b = f.read(8096)
                    if not b:
                        break
                    hash.update(b)
            shutil.copy(args[1], os.path.join(self.image_dir, hash.hexdigest()))
            with session() as _session:
                image = Image(checksum=hash.hexdigest(),
                              name=args[2])
                _session.add(image)
        else:
            raise UsageException()

    def delete(self, *args, **kwargs):
        if len(args) == 1:
            with session() as _session:
                _session.
            self._delete("/images", **{"id": args[0]})
        else:
            raise UsageException()

class VolumeCommand(AbstractCommand):
    """
    stack volume list
    stack volume create --sie 1 name
    stack volume delete uuid
    """
    actions = ["list", "create", "delete"]

    def execute(self, action, *args, **kwargs):
        pass


class FlavorCommand(AbstractCommand):
    """
    stack flavor list
    stack flavor create --vcpu 1 --memory 1024 --root 1 name
    stack flavor delete uuid
    """
    actions = ["list", "create", "delete"]
    fields = ["id", "uuid", "name", "vcpu", "memory", "root"]

    def list(self, *args, **kwargs):
        flavors = []
        for flavor in flavors:
            row = self.get_row(flavor)
            self.table.add_row(row)
        print self.table

    def create(self, *args, **kwargs):
        if len(args) == 7:
            data = {}
            for i in range(0, 6, 2):
                data[args[i][2:]] = int(args[i+1])
            data["name"] = args[6]
            self._post("/flavors", **data)
        else:
            raise UsageException()

    def delete(self, *args, **kwargs):
        if len(args) == 1:
            self._delete("/flavors", **{"id": args[0]})
        else:
            raise UsageException()

class ServerCommand(AbstractCommand):
    """
    stack server list
    stack server create --flavor flavor --image image --network network name
    stack server delete uuid
    """

    def execute(self, action, *args, **kwargs):
        pass


class NetworkCommand(AbstractCommand):
    """
    stack network list
    stack network create 
    stack network delete uuid
    """

    def execute(self, action, *args, **kwargs):
        pass


class PortCommand(AbstractCommand):
    """
    stack port list
    stack port create
    stack port delete uuid
    """

    def execute(self, action, *args, **kwargs):
        pass


def main():
    if len(sys.argv) == 1:
        usage()
    if len(sys.argv) == 2:
        if sys.argv[1] in _commands:
            usage(sys.argv[1])
        else:
            usage()
    if len(sys.argv) >= 3:
        if sys.argv[1] in _commands:
            command = get_commands_mapping()[sys.argv[1]]
            if sys.argv[2] in command.actions:
                command().execute(sys.argv[2], *sys.argv[3:])
            else:
                usage(sys.argv[1])
        else:
            usage()


main()
